package com.zlzlib.manager.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.github.yulichang.base.MPJBaseMapper;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.zlzlib.common.bean.EnumVo;
import com.zlzlib.common.bean.PageDataDto;
import com.zlzlib.mybatis.BasePo;
import com.zlzlib.mybatis.BaseServiceImpl;
import com.zlzlib.vuePage.config.FormSelectData;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

/**
 * @DateTime: 2024/5/23 11:14
 * @Author zlz
 * @Version 1.0
 */
public abstract class BaseManagerServiceImpl<PO extends BasePo, LV, FD extends PageDataDto,
        M extends MPJBaseMapper<PO>> extends BaseServiceImpl<M, PO>
        implements BaseManagerService<PO, LV, FD>, FormSelectData {

    protected Class<PO> poClazz = (Class<PO>) ((ParameterizedType)
            getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    protected Class<LV> lvClazz = (Class<LV>) ((ParameterizedType)
            getClass().getGenericSuperclass()).getActualTypeArguments()[1];

    @Override
    public Page<LV> findPageByCondition(FD dto) {
        MPJLambdaWrapper<PO> wrapper = new MPJLambdaWrapper<>();
        makeToLvWrapper(wrapper);
        makeFindPageWrapper(wrapper, dto);
        makeFindPageOrderWrapper(wrapper, dto);
        Page<LV> page = selectJoinListPage(PageDTO.of(dto.getCurrent(), dto.getSize()),
                lvClazz, wrapper);
        pageDataCover(page);
        return page;
    }

    @Override
    public LV findDataById(Long id) {
        MPJLambdaWrapper<PO> wrapper = new MPJLambdaWrapper<>();
        makeToLvWrapper(wrapper);
        wrapper.eq(getIdFunc(), id);
        return getBaseMapper().selectJoinOne(lvClazz, wrapper);
    }

    @Override
    public List<EnumVo> findConditionList(Object key) {
        return findConditionFunc(key, null);
    }

    @Override
    public List<EnumVo> findConditionListChild(Object key) {
        return findConditionFunc(null, key);
    }

    private List<EnumVo> findConditionFunc(Object keyParent, Object keyChild) {
        List<EnumVo> res = new ArrayList<>();
        LambdaQueryWrapper<PO> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(getConditionSelectFunc());
        if (!ObjectUtils.isEmpty(keyParent)) {
            //添加条件
            makeConditionWrapper(wrapper, keyParent);
        }
        if (!ObjectUtils.isEmpty(keyChild)) {
            //添加条件
            makeConditionChildWrapper(wrapper, keyChild);
        }
        List<PO> list = list(wrapper);
        for (PO po : list) {
            res.add(poToEnumVo(po));
        }
        return res;
    }

    /**
     * 如果不设置默认查询全部字段
     *
     * @return 设置条件查询的项目
     */
    protected abstract SFunction<PO, ?>[] getConditionSelectFunc();

    /**
     * 对象转化为查询条件类
     *
     * @param po 对象
     * @return 查询条件类
     */
    protected abstract EnumVo poToEnumVo(PO po);

    /**
     * 父类查询条件
     *
     * @param wrapper 条件
     * @param key     参数
     */
    protected void makeConditionWrapper(LambdaQueryWrapper<PO> wrapper, Object key) {
    }

    /**
     * 子类查询条件
     *
     * @param wrapper 条件
     * @param key     参数
     */
    protected void makeConditionChildWrapper(LambdaQueryWrapper<PO> wrapper, Object key) {
    }

    /**
     * 组合查询条件
     *
     * @param wrapper 条件
     * @param dto     参数
     */
    protected abstract void makeFindPageWrapper(MPJLambdaWrapper<PO> wrapper, FD dto);

    /**
     * 分页查询排序默认查询id
     *
     * @param wrapper 条件
     * @param dto     参数
     */
    protected void makeFindPageOrderWrapper(MPJLambdaWrapper<PO> wrapper, FD dto) {
        wrapper.orderBy(true, dto.isAsc(), getIdFunc());
    }

    /**
     * 转化分页数据
     *
     * @param page 分页数据
     */
    protected void pageDataCover(Page<LV> page) {
    }

    /**
     * 创建lv转化条件wrapper
     *
     * @param wrapper 条件
     */
    protected void makeToLvWrapper(MPJLambdaWrapper<PO> wrapper) {
        wrapper.selectAsClass(poClazz, lvClazz);
    }

    protected abstract SFunction<PO, ?> getIdFunc();
}
